//замыкания
(function () {
    Function.prototype.bind = function () {
        var args = Array.prototype.slice.call(arguments, 0),
            handler = this;

        return function () {
            arguments = Array.prototype.slice.call(arguments, 0);
            return handler.apply(this, args.concat(arguments));
        };
    };

    var fn1 = function () {
      console.log("f1 ", arguments);
    }

    function fn2 () {
      console.log("f2 ", arguments);
    }

    fn1 = fn1.bind(1);
    fn1 = fn1.bind(2);
    fn1 = fn1.bind(3);
    fn1(4); // [1, 2, 3, 4]
    fn1 = fn1.bind(5, 6);
    fn1(); // [1, 2, 3, 5, 6]

    fn2 = fn2.bind(10, 11);
    fn2(12, 13); // 10, 11, 12, 13
})();

(function () {
    var i = 10;
    function f (i) {
        console.log("i = ", i);
    }
    while (i--) {
        setTimeout(function () {
            f(i); // -1
        }, 0);
    }
})();

(function () {
    var i = 10;
    function f (i) {
        console.log("i = ", i);
    }
    while (i--) {
        setTimeout((function (i) {
            return function () {
                f(i); // [9, 0]
            }
        })(i), 0);
    }
})();

//всплытие
(function () {
    var f1 = function () {return "global f1"};
    function f2 () {return "global f2"}

    console.log(typeof f1 === "function" ? f1() : "f1 - " + typeof f1); // global f1
    console.log(typeof f2 === "function" ? f2() : "f2 - " + typeof f2); // global f2

    (function () {
        console.log("f1 - ", typeof f1, ", f2 - ", typeof f2); // undefined function

        console.log(typeof f1 === "function" ? f1() : "f1 - " + typeof f1); // f1 - undefined
        console.log(typeof f2 === "function" ? f2() : "f2 - " + typeof f2); // local f2

        var f1 = function () {return "local f1"};
        function f2 () {return "local f2"}

        console.log(typeof f1 === "function" ? f1() : "f1 - " + typeof f1); // local f1
        console.log(typeof f2 === "function" ? f2() : "f2 - " + typeof f2); // local f2
    })()
})();

//scope
(function () {
    var a = "a";
    function f1 () {
        var b = "b";
        function f2 () {
            var c = "c";
            console.log("f2: ", "a = ", typeof a === "string" ? a : "undefined"); // f2: a = a
            console.log("f2: ", "b = ", typeof b === "string" ? b : "undefined"); // f2: b = b
            console.log("f2: ", "c = ", typeof c === "string" ? c : "undefined"); // f2: c = c
        }
        f2();
        console.log("f1: ", "a = ", typeof a === "string" ? a : "undefined"); // f1: a = a
        console.log("f1: ", "b = ", typeof b === "string" ? b : "undefined"); // f1: b = b
        console.log("f1: ", "c = ", typeof c === "string" ? c : "undefined"); // f1: c = undefined
    }
    f1();
})();

(function () {
    function f1 () {
        var b = 0;
        return function () {
            return "b = " + ++b;
        };
    }
    f1 = f1();
    console.log(f1(), ", ", f1(), ", ", f1()); // b = 1 , b = 2 , b = 3
})();

(function () {
    var x = 1, y = 2;
    console.log("x = ", x, ", y = ", y); // x = 1, y = 2
    with ({x: 10}) {
        var x = 3, y = 4;
        console.log("x = ", x, ", y = ", y); // x = 3, y = 4
    }
    console.log("x = ", x, ", y = ", y); // x = 1, y = 4
})();




